{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Feast Operator with RBAC Configuration\n",
    "## Objective\n",
    "\n",
    "This demo provides a reference implementation of a runbook on how to enable Role-Based Access Control (RBAC) for Feast using the Feast Operator with the Kubernetes authentication type. This serves as useful reference material for a cluster admin / MLOps engineer.\n",
    "\n",
    "The demo steps include deploying the Feast Operator, creating Feast instances with server components (registry, offline store, online store), and Feast client testing locally and fom the Kubernetes. The goal is to ensure secure access control for Feast instances deployed by the Feast Operator.\n",
    " \n",
    "Please read these reference documents for understanding the Feast RBAC framework.\n",
    "- [RBAC Architecture](https://docs.feast.dev/v/master/getting-started/architecture/rbac) \n",
    "- [RBAC Permission](https://docs.feast.dev/v/master/getting-started/concepts/permission).\n",
    "- [RBAC Authorization Manager](https://docs.feast.dev/v/master/getting-started/components/authz_manager)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Deployment Architecture\n",
    "In this notebook, we will deploy a distributed topology of Feast services, which includes:\n",
    "\n",
    "* `Registry Server`: Handles metadata storage for feature definitions.\n",
    "* `Online Store Server`: Uses the `Registry Server` to query metadata and is responsible for low-latency serving of features.\n",
    "* `Offline Store Server`: Uses the `Registry Server` to query metadata and provides access to batch data for historical feature retrieval.\n",
    "\n",
    "Additionally, we will cover:\n",
    "* RBAC Configuration with Kubernetes Authentication for Feast resources."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prerequisites\n",
    "* Kubernetes Cluster\n",
    "* [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) Kubernetes CLI tool."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Install Prerequisites\n",
    "The following commands install and configure all the prerequisites on a MacOS environment. You can find the\n",
    "equivalent instructions on the offical documentation pages:\n",
    "* Install the `kubectl` cli.\n",
    "* Install Kubernetes and Container runtime (e.g. [Colima](https://github.com/abiosoft/colima)).\n",
    "  * Alternatively, authenticate to an existing Kubernetes or OpenShift cluster.\n",
    "  \n",
    "```bash\n",
    "brew install colima kubectl\n",
    "colima start -r containerd -k -m 3 -d 100 -c 2 --cpu-type max -a x86_64\n",
    "colima list\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:47:46.558319Z",
     "start_time": "2025-03-14T14:47:46.117084Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "namespace/feast created\n",
      "Context \"kind-kind\" modified.\n"
     ]
    }
   ],
   "source": [
    "!kubectl create ns feast\n",
    "!kubectl config set-context --current --namespace feast"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Validate the cluster setup:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:47:52.996466Z",
     "start_time": "2025-03-14T14:47:52.827264Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NAME    STATUS   AGE\n",
      "feast   Active   21s\n"
     ]
    }
   ],
   "source": [
    "!kubectl get ns feast"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Feast Admin Steps:\n",
    "Feast Admins or MLOps Engineers may require Kubernetes Cluster Admin roles when working with OpenShift or Kubernetes clusters. Below is the list of steps Required to set up Feast RBAC with the Operator by an Admin or MLOps Engineer.\n",
    "\n",
    "1. **Install the Feast Operator**\n",
    "2. **Install the Feast services via FeatureStore CR**\n",
    "3. **Configure the RBAC Permissions**\n",
    "4. **Perform Feast Apply**\n",
    "5. **Setting Service Account and Role Binding**\n",
    "\n",
    "## Install the Feast Operator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:48:42.482143Z",
     "start_time": "2025-03-14T14:48:29.671332Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "namespace/feast-operator-system created\n",
      "customresourcedefinition.apiextensions.k8s.io/featurestores.feast.dev created\n",
      "serviceaccount/feast-operator-controller-manager created\n",
      "role.rbac.authorization.k8s.io/feast-operator-leader-election-role created\n",
      "clusterrole.rbac.authorization.k8s.io/feast-operator-featurestore-editor-role created\n",
      "clusterrole.rbac.authorization.k8s.io/feast-operator-featurestore-viewer-role created\n",
      "clusterrole.rbac.authorization.k8s.io/feast-operator-manager-role created\n",
      "clusterrole.rbac.authorization.k8s.io/feast-operator-metrics-auth-role created\n",
      "clusterrole.rbac.authorization.k8s.io/feast-operator-metrics-reader created\n",
      "rolebinding.rbac.authorization.k8s.io/feast-operator-leader-election-rolebinding created\n",
      "clusterrolebinding.rbac.authorization.k8s.io/feast-operator-manager-rolebinding created\n",
      "clusterrolebinding.rbac.authorization.k8s.io/feast-operator-metrics-auth-rolebinding created\n",
      "service/feast-operator-controller-manager-metrics-service created\n",
      "deployment.apps/feast-operator-controller-manager created\n",
      "deployment.apps/feast-operator-controller-manager condition met\n"
     ]
    }
   ],
   "source": [
    "## Use this install command from a stable branch  \n",
    "!kubectl apply -f ../../infra/feast-operator/dist/install.yaml\n",
    "\n",
    "## OR, for the latest code/builds, use one the following commands from the 'master' branch\n",
    "# !make -C ../../infra/feast-operator install deploy IMG=quay.io/feastdev-ci/feast-operator:develop FS_IMG=quay.io/feastdev-ci/feature-server:develop\n",
    "# !make -C ../../infra/feast-operator install deploy IMG=quay.io/feastdev-ci/feast-operator:$(git rev-parse HEAD) FS_IMG=quay.io/feastdev-ci/feature-server:$(git rev-parse HEAD)\n",
    "\n",
    "!kubectl wait --for=condition=available --timeout=5m deployment/feast-operator-controller-manager -n feast-operator-system"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Install the Feast services via FeatureStore CR\n",
    "Next, we'll use the running Feast Operator to install the feast services with Server components online, offline, registry with kubernetes Authorization set. Apply the included [reference deployment](../../infra/feast-operator/config/samples/v1alpha1_featurestore_kubernetes_auth.yaml) to install and configure Feast with kubernetes Authorization ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:48:55.797775Z",
     "start_time": "2025-03-14T14:48:55.453327Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "apiVersion: feast.dev/v1alpha1\n",
      "kind: FeatureStore\n",
      "metadata:\n",
      "  name: sample-kubernetes-auth\n",
      "spec:\n",
      "  feastProject: feast_rbac\n",
      "  authz:\n",
      "    kubernetes:\n",
      "      roles:\n",
      "        - feast-writer\n",
      "        - feast-reader\n",
      "  services:\n",
      "    offlineStore:\n",
      "      server: {}\n",
      "    onlineStore:\n",
      "      server: {}\n",
      "    registry:\n",
      "      local:\n",
      "        server: {}\n",
      "    ui: {}\n",
      "featurestore.feast.dev/sample-kubernetes-auth created\n"
     ]
    }
   ],
   "source": [
    "!cat ../../infra/feast-operator/config/samples/v1alpha1_featurestore_kubernetes_auth.yaml\n",
    "!kubectl apply -f ../../infra/feast-operator/config/samples/v1alpha1_featurestore_kubernetes_auth.yaml -n feast"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Validate the running FeatureStore deployment\n",
    "Validate the deployment status."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:49:24.996009Z",
     "start_time": "2025-03-14T14:49:24.507177Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NAME                                                READY   STATUS     RESTARTS   AGE\n",
      "pod/feast-sample-kubernetes-auth-85dfdb76c8-ndl8c   0/4     Init:0/1   0          31s\n",
      "\n",
      "NAME                                            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE\n",
      "service/feast-sample-kubernetes-auth-offline    ClusterIP   10.96.42.112    <none>        80/TCP    31s\n",
      "service/feast-sample-kubernetes-auth-online     ClusterIP   10.96.61.239    <none>        80/TCP    31s\n",
      "service/feast-sample-kubernetes-auth-registry   ClusterIP   10.96.53.168    <none>        80/TCP    31s\n",
      "service/feast-sample-kubernetes-auth-ui         ClusterIP   10.96.110.102   <none>        80/TCP    31s\n",
      "\n",
      "NAME                                           READY   UP-TO-DATE   AVAILABLE   AGE\n",
      "deployment.apps/feast-sample-kubernetes-auth   0/1     1            0           31s\n",
      "\n",
      "NAME                                                      DESIRED   CURRENT   READY   AGE\n",
      "replicaset.apps/feast-sample-kubernetes-auth-85dfdb76c8   1         1         0       31s\n",
      "\n",
      "NAME                                         SCHEDULE   TIMEZONE   SUSPEND   ACTIVE   LAST SCHEDULE   AGE\n",
      "cronjob.batch/feast-sample-kubernetes-auth   @yearly    <none>     True      0        <none>          31s\n",
      "deployment.apps/feast-sample-kubernetes-auth condition met\n"
     ]
    }
   ],
   "source": [
    "!kubectl get all\n",
    "!kubectl wait --for=condition=available --timeout=8m deployment/feast-sample-kubernetes-auth"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Validate that the FeatureStore CR is in a `Ready` state."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:49:32.148636Z",
     "start_time": "2025-03-14T14:49:31.981954Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NAME                     STATUS   AGE\n",
      "sample-kubernetes-auth   Ready    4m21s\n"
     ]
    }
   ],
   "source": [
    "!kubectl get feast"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Configure the RBAC Permissions\n",
    "As we have created Kubernetes roles in FeatureStore CR to manage access control for Feast objects, the Python script `permissions_apply.py` will apply these roles to configure permissions. See the detailed code example below with comments."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:49:39.824642Z",
     "start_time": "2025-03-14T14:49:39.695940Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# Necessary modules for permissions and policies in Feast for RBAC\n",
      "from feast.feast_object import ALL_RESOURCE_TYPES\n",
      "from feast.permissions.action import READ, AuthzedAction, ALL_ACTIONS\n",
      "from feast.permissions.permission import Permission\n",
      "from feast.permissions.policy import RoleBasedPolicy\n",
      "\n",
      "# Define K8s roles same as created with FeatureStore CR\n",
      "admin_roles = [\"feast-writer\"]  # Full access (can create, update, delete ) Feast Resources\n",
      "user_roles = [\"feast-reader\"]   # Read-only access on Feast Resources\n",
      "\n",
      "# User permissions (feast_user_permission)\n",
      "# - Grants read and describing Feast objects access\n",
      "user_perm = Permission(\n",
      "    name=\"feast_user_permission\",\n",
      "    types=ALL_RESOURCE_TYPES,\n",
      "    policy=RoleBasedPolicy(roles=user_roles),\n",
      "    actions=[AuthzedAction.DESCRIBE] + READ  # Read access (READ_ONLINE, READ_OFFLINE) + describe other Feast Resources.\n",
      ")\n",
      "\n",
      "# Admin permissions (feast_admin_permission)\n",
      "# - Grants full control over all resources\n",
      "admin_perm = Permission(\n",
      "    name=\"feast_admin_permission\",\n",
      "    types=ALL_RESOURCE_TYPES,\n",
      "    policy=RoleBasedPolicy(roles=admin_roles),\n",
      "    actions=ALL_ACTIONS  # Full permissions: CREATE, UPDATE, DELETE, READ, WRITE\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "#view the permissions  \n",
    "!cat  permissions_apply.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:49:45.670402Z",
     "start_time": "2025-03-14T14:49:45.248755Z"
    }
   },
   "outputs": [],
   "source": [
    "# Copy the Permissions to the pods under feature_repo directory\n",
    "!kubectl cp permissions_apply.py $(kubectl get pods -l 'feast.dev/name=sample-kubernetes-auth' -ojsonpath=\"{.items[*].metadata.name}\"):/feast-data/feast_rbac/feature_repo -c online"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:49:51.754691Z",
     "start_time": "2025-03-14T14:49:51.466463Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "project: feast_rbac\n",
      "provider: local\n",
      "offline_store:\n",
      "    type: dask\n",
      "online_store:\n",
      "    path: /feast-data/online_store.db\n",
      "    type: sqlite\n",
      "registry:\n",
      "    path: /feast-data/registry.db\n",
      "    registry_type: file\n",
      "auth:\n",
      "    type: kubernetes\n",
      "entity_key_serialization_version: 3\n"
     ]
    }
   ],
   "source": [
    "#view the feature_store.yaml configuration \n",
    "!kubectl exec deploy/feast-sample-kubernetes-auth -itc online -- cat feature_store.yaml"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Apply the Permissions and Feast Object to Registry"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:50:07.432351Z",
     "start_time": "2025-03-14T14:49:56.731316Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<jemalloc>: MADV_DONTNEED does not work (memset will be used instead)\n",
      "<jemalloc>: (This is the expected behaviour if you are running under QEMU)\n",
      "/opt/app-root/lib64/python3.11/site-packages/pydantic/_internal/_fields.py:192: UserWarning: Field name \"vector_enabled\" in \"SqliteOnlineStoreConfig\" shadows an attribute in parent \"VectorStoreConfig\"\n",
      "  warnings.warn(\n",
      "/feast-data/feast_rbac/feature_repo/example_repo.py:27: DeprecationWarning: Entity value_type will be mandatory in the next release. Please specify a value_type for entity 'driver'.\n",
      "  driver = Entity(name=\"driver\", join_keys=[\"driver_id\"])\n",
      "Applying changes for project feast_rbac\n",
      "/opt/app-root/lib64/python3.11/site-packages/feast/feature_store.py:580: RuntimeWarning: On demand feature view is an experimental feature. This API is stable, but the functionality does not scale well for offline retrieval\n",
      "  warnings.warn(\n",
      "Created project \u001b[1m\u001b[32mfeast_rbac\u001b[0m\n",
      "Created entity \u001b[1m\u001b[32mdriver\u001b[0m\n",
      "Created feature view \u001b[1m\u001b[32mdriver_hourly_stats\u001b[0m\n",
      "Created feature view \u001b[1m\u001b[32mdriver_hourly_stats_fresh\u001b[0m\n",
      "Created on demand feature view \u001b[1m\u001b[32mtransformed_conv_rate\u001b[0m\n",
      "Created on demand feature view \u001b[1m\u001b[32mtransformed_conv_rate_fresh\u001b[0m\n",
      "Created feature service \u001b[1m\u001b[32mdriver_activity_v2\u001b[0m\n",
      "Created feature service \u001b[1m\u001b[32mdriver_activity_v1\u001b[0m\n",
      "Created feature service \u001b[1m\u001b[32mdriver_activity_v3\u001b[0m\n",
      "Created permission \u001b[1m\u001b[32mfeast_user_permission\u001b[0m\n",
      "Created permission \u001b[1m\u001b[32mfeast_admin_permission\u001b[0m\n",
      "\n",
      "Created sqlite table \u001b[1m\u001b[32mfeast_rbac_driver_hourly_stats_fresh\u001b[0m\n",
      "Created sqlite table \u001b[1m\u001b[32mfeast_rbac_driver_hourly_stats\u001b[0m\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!kubectl exec deploy/feast-sample-kubernetes-auth -itc online -- feast apply"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**List the applied permission details permissions on Feast Resources.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:50:59.527146Z",
     "start_time": "2025-03-14T14:50:15.549290Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<jemalloc>: MADV_DONTNEED does not work (memset will be used instead)\n",
      "<jemalloc>: (This is the expected behaviour if you are running under QEMU)\n",
      "/opt/app-root/lib64/python3.11/site-packages/pydantic/_internal/_fields.py:192: UserWarning: Field name \"vector_enabled\" in \"SqliteOnlineStoreConfig\" shadows an attribute in parent \"VectorStoreConfig\"\n",
      "  warnings.warn(\n",
      "+--------------+\n",
      "| ROLE NAME    |\n",
      "+==============+\n",
      "| feast-reader |\n",
      "+--------------+\n",
      "| feast-writer |\n",
      "+--------------+\n",
      "<jemalloc>: MADV_DONTNEED does not work (memset will be used instead)\n",
      "<jemalloc>: (This is the expected behaviour if you are running under QEMU)\n",
      "/opt/app-root/lib64/python3.11/site-packages/pydantic/_internal/_fields.py:192: UserWarning: Field name \"vector_enabled\" in \"SqliteOnlineStoreConfig\" shadows an attribute in parent \"VectorStoreConfig\"\n",
      "  warnings.warn(\n",
      "NAME                    TYPES                NAME_PATTERNS    ACTIONS        ROLES         REQUIRED_TAGS\n",
      "feast_user_permission   Project              -                DESCRIBE       feast-reader  -\n",
      "                        FeatureView                           READ_OFFLINE\n",
      "                        OnDemandFeatureView                   READ_ONLINE\n",
      "                        BatchFeatureView\n",
      "                        StreamFeatureView\n",
      "                        Entity\n",
      "                        FeatureService\n",
      "                        DataSource\n",
      "                        ValidationReference\n",
      "                        SavedDataset\n",
      "                        Permission\n",
      "feast_admin_permission  Project              -                CREATE         feast-writer  -\n",
      "                        FeatureView                           DESCRIBE\n",
      "                        OnDemandFeatureView                   UPDATE\n",
      "                        BatchFeatureView                      DELETE\n",
      "                        StreamFeatureView                     READ_ONLINE\n",
      "                        Entity                                READ_OFFLINE\n",
      "                        FeatureService                        WRITE_ONLINE\n",
      "                        DataSource                            WRITE_OFFLINE\n",
      "                        ValidationReference\n",
      "                        SavedDataset\n",
      "                        Permission\n",
      "<jemalloc>: MADV_DONTNEED does not work (memset will be used instead)\n",
      "<jemalloc>: (This is the expected behaviour if you are running under QEMU)\n",
      "/opt/app-root/lib64/python3.11/site-packages/pydantic/_internal/_fields.py:192: UserWarning: Field name \"vector_enabled\" in \"SqliteOnlineStoreConfig\" shadows an attribute in parent \"VectorStoreConfig\"\n",
      "  warnings.warn(\n",
      "spec:\n",
      "  name: feast_admin_permission\n",
      "  types:\n",
      "  - PROJECT\n",
      "  - FEATURE_VIEW\n",
      "  - ON_DEMAND_FEATURE_VIEW\n",
      "  - BATCH_FEATURE_VIEW\n",
      "  - STREAM_FEATURE_VIEW\n",
      "  - ENTITY\n",
      "  - FEATURE_SERVICE\n",
      "  - DATA_SOURCE\n",
      "  - VALIDATION_REFERENCE\n",
      "  - SAVED_DATASET\n",
      "  - PERMISSION\n",
      "  actions:\n",
      "  - CREATE\n",
      "  - DESCRIBE\n",
      "  - UPDATE\n",
      "  - DELETE\n",
      "  - READ_ONLINE\n",
      "  - READ_OFFLINE\n",
      "  - WRITE_ONLINE\n",
      "  - WRITE_OFFLINE\n",
      "  policy:\n",
      "    roleBasedPolicy:\n",
      "      roles:\n",
      "      - feast-writer\n",
      "meta:\n",
      "  createdTimestamp: '2025-05-29T11:28:41.322952Z'\n",
      "  lastUpdatedTimestamp: '2025-05-29T11:28:41.322952Z'\n",
      "\n",
      "<jemalloc>: MADV_DONTNEED does not work (memset will be used instead)\n",
      "<jemalloc>: (This is the expected behaviour if you are running under QEMU)\n",
      "/opt/app-root/lib64/python3.11/site-packages/pydantic/_internal/_fields.py:192: UserWarning: Field name \"vector_enabled\" in \"SqliteOnlineStoreConfig\" shadows an attribute in parent \"VectorStoreConfig\"\n",
      "  warnings.warn(\n",
      "spec:\n",
      "  name: feast_user_permission\n",
      "  types:\n",
      "  - PROJECT\n",
      "  - FEATURE_VIEW\n",
      "  - ON_DEMAND_FEATURE_VIEW\n",
      "  - BATCH_FEATURE_VIEW\n",
      "  - STREAM_FEATURE_VIEW\n",
      "  - ENTITY\n",
      "  - FEATURE_SERVICE\n",
      "  - DATA_SOURCE\n",
      "  - VALIDATION_REFERENCE\n",
      "  - SAVED_DATASET\n",
      "  - PERMISSION\n",
      "  actions:\n",
      "  - DESCRIBE\n",
      "  - READ_OFFLINE\n",
      "  - READ_ONLINE\n",
      "  policy:\n",
      "    roleBasedPolicy:\n",
      "      roles:\n",
      "      - feast-reader\n",
      "meta:\n",
      "  createdTimestamp: '2025-05-29T11:28:41.322160Z'\n",
      "  lastUpdatedTimestamp: '2025-05-29T11:28:41.322160Z'\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!kubectl exec deploy/feast-sample-kubernetes-auth -itc online -- feast permissions list-roles\n",
    "!kubectl exec deploy/feast-sample-kubernetes-auth -itc online -- feast permissions list\n",
    "!kubectl exec deploy/feast-sample-kubernetes-auth -itc online -- feast permissions describe feast_admin_permission\n",
    "!kubectl exec deploy/feast-sample-kubernetes-auth -itc online -- feast permissions describe feast_user_permission"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setting Up Service Account and RoleBinding \n",
    "The steps below will:\n",
    "- Create **three different ServiceAccounts** for Feast.\n",
    "- Assign appropriate **RoleBindings** for access control."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test Cases\n",
    "| User Type       | ServiceAccount               | RoleBinding Assigned | Expected Behavior in output                                |\n",
    "|----------------|-----------------------------|----------------------|------------------------------------------------------------|\n",
    "| **Read-Only**  | `feast-user-sa`              | `feast-reader`       | Can **read** from the feature store, but **cannot write**. |\n",
    "| **Unauthorized** | `feast-unauthorized-user-sa` | _None_               | **Access should be denied** in `test.py`.                  |\n",
    "| **Admin**      | `feast-admin-sa`             | `feast-writer`       | Can **read and write** feature store data.                 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Set Up a Read-Only Feast User \n",
    "(ServiceAccount: feast-user-sa, Role: feast-reader)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:55:47.715282Z",
     "start_time": "2025-03-14T14:55:47.045535Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating ServiceAccount: feast-user-sa\n",
      "serviceaccount/feast-user-sa created\n",
      "Assigning Read-Only RoleBinding: feast-user-rolebinding\n",
      "rolebinding.rbac.authorization.k8s.io/feast-user-rolebinding created\n"
     ]
    }
   ],
   "source": [
    "# Step 1: Create the ServiceAccount\n",
    "!echo \"Creating ServiceAccount: feast-user-sa\"\n",
    "!kubectl create serviceaccount feast-user-sa -n feast\n",
    "\n",
    "# Step 2: Assign RoleBinding (Read-Only Access for Feast)\n",
    "!echo \"Assigning Read-Only RoleBinding: feast-user-rolebinding\"\n",
    "!kubectl create rolebinding feast-user-rolebinding --role=feast-reader --serviceaccount=feast:feast-user-sa -n feast"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Set Up an Unauthorized Feast User\n",
    "(ServiceAccount: feast-unauthorized-user-sa, Role: None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:55:53.079167Z",
     "start_time": "2025-03-14T14:55:52.795933Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating Unauthorized ServiceAccount: feast-unauthorized-user-sa\n",
      "serviceaccount/feast-unauthorized-user-sa created\n"
     ]
    }
   ],
   "source": [
    "# Create the ServiceAccount (Without RoleBinding)\n",
    "!echo \"Creating Unauthorized ServiceAccount: feast-unauthorized-user-sa\"\n",
    "!kubectl create serviceaccount feast-unauthorized-user-sa -n feast\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Set Up a Test Admin Feast User\n",
    "(ServiceAccount: feast-admin-sa, Role: feast-writer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-14T14:55:59.103855Z",
     "start_time": "2025-03-14T14:55:58.548503Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating ServiceAccount: feast-admin-sa\n",
      "serviceaccount/feast-admin-sa created\n",
      "Assigning Admin RoleBinding: feast-admin-rolebinding\n",
      "rolebinding.rbac.authorization.k8s.io/feast-admin-rolebinding created\n"
     ]
    }
   ],
   "source": [
    "# Create the ServiceAccount\n",
    "!echo \"Creating ServiceAccount: feast-admin-sa\"\n",
    "!kubectl create serviceaccount feast-admin-sa -n feast\n",
    "\n",
    "# Assign RoleBinding (Admin Access for Feast)\n",
    "!echo \"Assigning Admin RoleBinding: feast-admin-rolebinding\"\n",
    "!kubectl create rolebinding feast-admin-rolebinding --role=feast-writer --serviceaccount=feast:feast-admin-sa -n feast\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[Next: Client example from Pod](./2-client-rbac-test-pod.ipynb)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
